/*
 *  Copyright (C) 2009  Peter Kist & Jan Ripke
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "Entity.h"

#include <sstream>

#include "Property.h"
#include "Behavior.h"
#include "PropertyFactory.h"
#include "BehaviorFactory.h"

namespace galaxy {
    namespace world {

        int Entity::m_NameGenCount = 1;

        Entity::Entity(EntityPtr const& ownerEntity)
        {
            getGeneratedName (m_Name);

            EntityPtr * myself = new EntityPtr();
            myself->reset (this);
            ownerEntity->m_Owns.insert (*myself);
            m_Owner = ownerEntity;
        }

        Entity::Entity(EntityPtr const & ownerEntity, std::string name) {
            if (name.length() > 0) m_Name = name;
            else getGeneratedName (m_Name);

            EntityPtr * myself = new EntityPtr ();
            myself->reset(this);
            ownerEntity->m_Owns.insert (*myself);
            this->m_Owner = ownerEntity;
        }

        Entity::~Entity(void)
        {
            m_Owner.reset();
            m_Owns.clear();
        }

        bool Entity::addBehavior (std::string& name, Behavior::Status initialState) {
            if (! findBehavior (name)) {
                Behavior * behavior = BehaviorFactory::createBehavior (name);
                if (behavior) {
                    behavior->setOwner(*this);
                    m_Behaviors[name] = behavior;

                    bool result = behavior->initialize();
                    behavior->setState(result ? initialState : Behavior::CREATED);
                    return result;
                } 
            }
            return false;
        }

        Behavior * Entity::findBehavior (std::string& name) {
            BehaviorMap::iterator i = m_Behaviors.find(name);
            if (i != m_Behaviors.end()) {
                return (Behavior *) i->second;
            }
            return (Behavior *) 0L;
        }

        PropertyPtr Entity::obtainProperty (std::string& name) {
            PropertyMap::iterator iter = findProperty(name);
            if (iter != m_Properties.end()) {
                return iter->second;
            }

            PropertyPtr property (PropertyFactory::createProperty(name));
            return property;
        }


        Entity::PropertyMap::iterator Entity::findProperty (std::string& name) {
            return m_Properties.find(name);
        }

        bool Entity::removeProperty (std::string& name) {
            PropertyMap::size_type size = m_Properties.erase(name);
            return (size > 0 ? true : false);
        }

        void Entity::getGeneratedName(std::string& name) {
            std::ostringstream generatedName;

            generatedName << "gn:" << 1 << ":" << m_NameGenCount++;
            name = generatedName.str();
        }

        bool Entity::isOwner (EntityPtr& entity) const {
            EntityPtr p = m_Owner.lock ();
            if (p == entity) {
                return true;
            } 
            return false;
        }

        bool Entity::changeOwner (EntityPtr newOwner) {

            EntityPtr currentOwner = m_Owner.lock();
            EntityPtr * myself = new EntityPtr();
            myself->reset (this);

            Entity::EntitySet::iterator i = currentOwner->m_Owns.find(*myself);
            if (i != currentOwner->m_Owns.end()) {
                currentOwner->m_Owns.erase (i);
            }

            if (newOwner) {
                newOwner->m_Owns.insert (*myself);
                m_Owner = newOwner;
            }

            return true;
        }

        /* TODO: refactor to use EntitySet::find */
        bool Entity::findOwned (std::string& name, EntityPtr& result) {        
            EntitySet::iterator iter = m_Owns.begin ();
            while (iter != m_Owns.end ()) {
                if ((*iter)->getName() == name) {
                    EntityPtr p;
                    p = *iter;
                    result = p;
                    return true;
                }
                iter++;
            }
            return false;
        }

    } // namespace world
} // namespace galaxy
